home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / dev / c / flash-0.4.3.lha / flash-0.4.3 / Lib / sound.cc < prev    next >
C/C++ Source or Header  |  1999-02-21  |  8KB  |  416 lines

  1. /////////////////////////////////////////////////////////////
  2. // Flash Plugin and Player
  3. // Copyright (C) 1998,1999 Olivier Debon
  4. // 
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. // 
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. // 
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18. // 
  19. ///////////////////////////////////////////////////////////////
  20. //  Author : Olivier Debon  <odebon@club-internet.fr>
  21. //
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <unistd.h>
  27. #include <fcntl.h>
  28. #include <sys/ioctl.h>
  29. #ifndef NOSOUND
  30. #include <linux/soundcard.h>
  31. #endif
  32. #include "sound.h"
  33.  
  34. static char *rcsid = "$Id: sound.cc,v 1.11 1999/01/31 21:14:22 olivier Exp $";
  35.  
  36. #define PRINT 0
  37.  
  38. //////////// SOUND
  39.  
  40. Sound::Sound(long id) : Character(SoundType, id)
  41. {
  42.     samples = 0;
  43.     stereo = 0;
  44.     soundRate = 0;
  45.     sampleSize = 1;
  46. }
  47.  
  48. Sound::~Sound()
  49. {
  50.     if (samples) {
  51.         delete samples;
  52.     }
  53. }
  54.  
  55. void
  56. Sound::setSoundFlags(long f) {
  57.     switch (GET_SOUND_RATE_CODE(f)) {
  58.         case 0:
  59.             soundRate = 5500;
  60.             break;
  61.         case 1:
  62.             soundRate = 11000;
  63.             break;
  64.         case 2:
  65.             soundRate = 22000;
  66.             break;
  67.         case 3:
  68.             soundRate = 44000;
  69.             break;
  70.     }
  71.     if (f & soundIs16bit) {
  72.         sampleSize = 2;
  73.     }
  74.     if (f & soundIsStereo) {
  75.         stereo = 1;
  76.     }
  77.  
  78. #if PRINT
  79.     printf("-----\nFlags = %2x\n", f);
  80.     printf("Rate = %d kHz  ", soundRate);
  81.     printf("SampleSize = %d byte(s) ", sampleSize);
  82.     if (f & soundIsStereo) {
  83.         printf("Stereo  ");
  84.     } else {
  85.         printf("Mono  ");
  86.     }
  87.     if (f & soundIsADPCMCompressed) {
  88.         printf("ADPCM\n");
  89.     } else {
  90.         printf("Raw\n");
  91.     }
  92. #endif
  93. }
  94.  
  95. char *
  96. Sound::setNbSamples(long n) {
  97.     long size;
  98.  
  99.     nbSamples = n;
  100.  
  101.     size = nbSamples * (stereo ? 2 : 1) * sampleSize;
  102.  
  103.     samples = new char[ size ];
  104.  
  105.     memset((char *)samples,0, size);
  106.  
  107.     return samples;
  108. }
  109.  
  110. long
  111. Sound::getRate() {
  112.     return soundRate;
  113. }
  114.  
  115. long
  116. Sound::getChannel() {
  117.     return stereo ? 2 : 1;
  118. }
  119.  
  120. long
  121. Sound::getNbSamples() {
  122.     return nbSamples;
  123. }
  124.  
  125. long
  126. Sound::getSampleSize() {
  127.     return sampleSize;
  128. }
  129.  
  130. char *
  131. Sound::getSamples() {
  132.     return samples;
  133. }
  134.  
  135. //////////// SOUND MIXER
  136.  
  137. long SoundMixer::dsp = -1;    // Init of descriptor
  138. long SoundMixer::blockSize = 0;    // Driver sound buffer size
  139. long SoundMixer::nbInst = 0;    // Nb SoundMixer instances
  140. long SoundMixer::sampleSize = 0;
  141. long SoundMixer::stereo = 0;
  142. long SoundMixer::soundRate = 0;
  143.  
  144. SoundMixer::SoundMixer(char *device)
  145. {
  146. #ifndef NOSOUND
  147.     int status;
  148.     long fmt;
  149.  
  150.     list = 0;    // No sound to play
  151.  
  152.     if (nbInst++) {
  153.         // Device is already open
  154.         return;
  155.     }
  156.  
  157.     dsp = open(device,O_WRONLY);
  158.     if (dsp < 0) {
  159.         perror("open dsp");
  160.         return;
  161.     }
  162.  
  163.     // Reset device
  164.     status = ioctl(dsp, SNDCTL_DSP_RESET);
  165.  
  166.     // Set sample size
  167.     fmt = AFMT_S16_LE;
  168.     sampleSize = 2;
  169.     status = ioctl(dsp, SNDCTL_DSP_SETFMT, &fmt);
  170.  
  171.     if (status) {
  172.         fmt = AFMT_U8;
  173.         sampleSize = 1;
  174.         status = ioctl(dsp, SNDCTL_DSP_SETFMT, &fmt);
  175.     }
  176.  
  177.     // Set stereo channel
  178.     stereo = 1;
  179.     status = ioctl(dsp, SNDCTL_DSP_STEREO, &stereo);
  180.  
  181.     if (status) {
  182.         stereo = 0;
  183.     }
  184.  
  185.     // Set sound rate in Hertz
  186.     soundRate = 11000;
  187.     status = ioctl(dsp, SNDCTL_DSP_SPEED, &soundRate);
  188.  
  189.     // Get device buffer size
  190.     status = ioctl(dsp, SNDCTL_DSP_GETBLKSIZE, &blockSize);
  191.     blockSize *= 2;
  192.  
  193.     buffer = (char *)malloc(blockSize);
  194.  
  195. #if PRINT
  196.     int caps;
  197.  
  198.     ioctl(dsp,SNDCTL_DSP_GETCAPS, &caps);
  199.     printf("Audio capabilities = %x\n", caps);
  200. #endif /* PRINT */
  201.  
  202. #endif    /* NOSOUND */
  203. }
  204.  
  205. SoundMixer::~SoundMixer()
  206. {
  207.     if (--nbInst == 0) {
  208.         close(dsp);
  209.         free(buffer);
  210.     }
  211. }
  212.  
  213. void
  214. SoundMixer::stopSounds()
  215. {
  216. #ifndef NOSOUND
  217.     SoundList *sl,*del;
  218.  
  219.     for(sl = list; sl; ) {
  220.         del = sl;
  221.         sl = sl->next;
  222.         delete del;
  223.     }
  224.     list = 0;
  225. #endif
  226. }
  227.  
  228. void
  229. SoundMixer::startSound(Sound *sound)
  230. {
  231.     SoundList *sl;
  232.  
  233.     if (sound) {
  234.         // Add sound in list
  235.         sl = new SoundList;
  236.         sl->rate = sound->getRate();
  237.         sl->stereo = (sound->getChannel() == 2);
  238.         sl->sampleSize = sound->getSampleSize();
  239.         sl->current = sound->getSamples();
  240.         sl->remaining = sound->getSampleSize()*sound->getNbSamples()*sound->getChannel();
  241.         sl->next = list;
  242.         list = sl;
  243.     }
  244. }
  245.  
  246. long
  247. SoundMixer::playSounds()
  248. {
  249. #ifndef NOSOUND
  250.     audio_buf_info     bufInfo;
  251.     long         nbBytes, n;
  252.     SoundList    *sl,*prev;
  253.     int         status;
  254.  
  255.     // Init failed
  256.     if (dsp < 0) return 0;
  257.  
  258.     // No sound to play
  259.     if (list == 0) return 0;
  260.  
  261.     // Get free DMA buffer space
  262.     status = ioctl(dsp, SNDCTL_DSP_GETOSPACE, &bufInfo);
  263.  
  264.     // Free space is not large enough to output data without blocking
  265.     // But there are still sounds to play. We must wait.
  266.     if (bufInfo.bytes < blockSize) return 1;
  267.  
  268.     nbBytes = 0;
  269.  
  270.     // Fill buffer with silence.
  271.     memset((void*)buffer, 0, blockSize);
  272.  
  273.     prev = 0;
  274.     sl = list;
  275.     while(sl) {
  276.  
  277.         // Ask sound to fill the buffer
  278.         // according to device capabilities
  279.         n = fillSoundBuffer(sl, buffer, blockSize);
  280.  
  281.         // Remember the largest written size
  282.         if (n > nbBytes) {
  283.             nbBytes = n;
  284.         }
  285.  
  286.         // No more samples for this sound
  287.         if (sl->remaining == 0) {
  288.             // Remove sound from list
  289.             if (prev) {
  290.                 prev->next = sl->next;
  291.                 delete sl;
  292.                 sl = prev->next;
  293.             } else {
  294.                 list = sl->next;
  295.                 delete sl;
  296.                 sl = list;
  297.             }
  298.         } else {
  299.             sl = sl->next;
  300.         }
  301.     }
  302.  
  303.     if (nbBytes) {
  304.         // At last ! Play It !
  305.         write(dsp,buffer,nbBytes);
  306.         status = ioctl(dsp, SNDCTL_DSP_POST);
  307.     }
  308.  
  309.     return nbBytes;
  310. #else
  311.     return 0;
  312. #endif
  313. }
  314.  
  315. long
  316. SoundMixer::fillSoundBuffer(SoundList *sl, char *buffer, long bufferSize)
  317. {
  318.     long sampleLeft, sampleRight;
  319.     long skipOut, skipOutInit;
  320.     long skipIn, skipInInit;
  321.     long freqRatio;
  322.     long totalOut = 0;
  323.  
  324.     freqRatio = sl->rate / soundRate;
  325.     if (freqRatio) {
  326.         skipOutInit = freqRatio - 1;
  327.         skipInInit = 0;
  328.     }
  329.  
  330.     freqRatio = soundRate / sl->rate;
  331.     if (freqRatio) {
  332.         skipInInit = freqRatio - 1;
  333.         skipOutInit = 0;
  334.     }
  335.  
  336.     skipOut = skipOutInit;
  337.     skipIn = skipInInit;
  338.     while (bufferSize && sl->remaining) {
  339.         if (skipIn-- == 0) {
  340.             // Get sampleLeft
  341.             if (sl->sampleSize == 2) {
  342.                 sampleLeft = (long)(*(short *)(sl->current));
  343.                 if (sampleSize == 1) {
  344.                     sampleLeft = (sampleLeft >> 8) &0xff;
  345.                 }
  346.             } else {
  347.                 sampleLeft = (long)*(sl->current);
  348.                 if (sampleSize == 2) {
  349.                     sampleLeft <<= 8;
  350.                 }
  351.             }
  352.             sl->current += sl->sampleSize;
  353.             sl->remaining -= sl->sampleSize;
  354.  
  355.             if (sl->stereo) {
  356.                 // Get sampleRight
  357.                 if (sl->sampleSize == 2) {
  358.                     sampleRight = (long)(*(short *)(sl->current));
  359.                     if (sampleSize == 1) {
  360.                         sampleRight = (sampleRight >> 8) &0xff;
  361.                     }
  362.                 } else {
  363.                     sampleRight = (long)*(sl->current);
  364.                     if (sampleSize == 2) {
  365.                         sampleRight <<= 8;
  366.                     }
  367.                 }
  368.                 sl->current += sl->sampleSize;
  369.                 sl->remaining -= sl->sampleSize;
  370.  
  371.             } else {
  372.                 sampleRight = sampleLeft;
  373.             }
  374.             
  375.             skipIn = skipInInit;
  376.         }
  377.  
  378.         if (skipOut-- == 0) {
  379.             // Output
  380.             if (stereo) {
  381.                 if (sampleSize == 2) {
  382.                     *((short *)buffer) += sampleLeft/2;
  383.                     bufferSize -= sampleSize;
  384.                     buffer += sampleSize;
  385.                     *((short *)buffer) += sampleRight/2;
  386.                     bufferSize -= sampleSize;
  387.                     buffer += sampleSize;
  388.                 } else {
  389.                     *((char *)buffer) += sampleLeft/2;
  390.                     bufferSize -= sampleSize;
  391.                     buffer += sampleSize;
  392.                     *((char *)buffer) += sampleRight/2;
  393.                     bufferSize -= sampleSize;
  394.                     buffer += sampleSize;
  395.                 }
  396.                 totalOut += 2*sampleSize;
  397.             } else {
  398.                 if (sampleSize == 2) {
  399.                     *((short *)buffer) += (sampleLeft+sampleRight)>>2;
  400.                     bufferSize -= sampleSize;
  401.                     buffer += sampleSize;
  402.                 } else {
  403.                     *((char *)buffer) += (sampleLeft+sampleRight)>>2;
  404.                     bufferSize -= sampleSize;
  405.                     buffer += sampleSize;
  406.                 }
  407.                 totalOut += sampleSize;
  408.             }
  409.  
  410.             skipOut = skipOutInit;
  411.         }
  412.     }
  413.  
  414.     return totalOut;
  415. }
  416.